<!--
 * @Description: 重要节点控制策划导入节点
 * @Author: wind-lc
 * @version: 1.0
 * @Date: 2022-02-18 10:07:55
 * @LastEditTime: 2022-02-28 17:51:32
 * @FilePath: \cscec-pms-admin\src\views\project\projectManagementPlanning\projectManagementPlanningComponents\components\ImportImportantNodes.vue
-->
<template>
  <BaseModal
    :visible="visible"
    title="导入节点"
    :width="GET_REDRESS_PERCENTAGE * 0.95+'vw'"
    :destroy-on-close="true"
    @cancel="handleModalCancel"
    @ok="handleConfirm"
  >
    <a-spin :spinning="loading">
      <template v-if="isHasData">
        <section class="import-important-nodes-wrapper">
          <a-checkbox
            :checked="controlLevel1.checked"
            :indeterminate="controlLevel1.indeterminate"
            @change="(e)=>handleSelectNode(1,e)"
          >
            一级节点({{ controlLevel1.length }}项)
          </a-checkbox>
          <a-checkbox
            :checked="controlLevel2.checked"
            :indeterminate="controlLevel2.indeterminate"
            @change="(e)=>handleSelectNode(2,e)"
          >
            二级节点({{ controlLevel2.length }}项)
          </a-checkbox>
          <a-checkbox
            :checked="controlLevel3.checked"
            :indeterminate="controlLevel3.indeterminate"
            @change="(e)=>handleSelectNode(3,e)"
          >
            三级节点({{ controlLevel3.length }}项)
          </a-checkbox>
          <a-checkbox
            class="all-checked"
            :checked="all.checked"
            :indeterminate="all.indeterminate"
            @change="(e)=>handleAll(e.target.checked)"
          />
        </section>
        <u-table
          ref="table"
          :height="500"
          row-id="id"
          row-key="id"
          :use-virtual="true"
          :big-data-checkbox="true"
          fixed-columns-roll
          show-header-overflow
          :row-height="48"
          select-tr-class="select"
          :highlight-current-row="false"
          :tree-config="{
            children: 'childTree',
            expandAll: false,
          }"
          border
          class="import-important-nodes-table"
        >
          <u-table-column
            v-for="item in columns"
            :key="item.dataIndex"
            :prop="item.dataIndex"
            :label="item.title"
            :width="item.width"
            :reserve-selection="true"
            :type="['selection','index'].includes(item.dataIndex)?item.dataIndex:''"
            :fixed="['selection','index','checkbox'].includes(item.dataIndex)"
            :tree-node="item.dataIndex === 'phaseCategory'"
            align="center"
          >
            <template
              v-if="!['selection','index'].includes(item.dataIndex)"
              v-slot="{ row }"
            >
              <span v-if="item.dataIndex === 'checkbox'">
                <a-checkbox
                  :checked="row.checked"
                  :indeterminate="row.indeterminate"
                  @change="(e)=>handleNodeChecked(row,e)"
                />
              </span>
              <span
                v-else
                class="span-ellipsis"
                :title="row[item.dataIndex]"
              >
                {{ row[item.dataIndex] }}
              </span>
            </template>
            <template slot="header">
              <!-- <a-checkbox
                v-if="item.dataIndex === 'checkbox'"
                :checked="all.checked"
                :indeterminate="all.indeterminate"
                @change="(e)=>handleAll(e.target.checked)"
              /> -->
              <span v-if="item.dataIndex !== 'checkbox'">{{ item.title }}</span>
            </template>
          </u-table-column>
        </u-table>
      </template>
      <template v-else>
        <p>项目重要节点内容由《施工进度总计划》中的一、二级节点数据提取，当前无重要节点数据，可能原因：</p>
        <p>1.未编制《施工进度总计划》；</p>
        <p>2.《施工进度总计划》未审批完成。</p>
      </template>
    </a-spin>
  </BaseModal>
</template>
<script>
import BaseModal from '@/components/BaseModal'
import { UTable, UTableColumn } from 'umy-ui'
import { controlPlanningImportantNodes } from '@/api/projectManagementPlanning/projectManagementPlanningSchedule'
import { mapGetters } from 'vuex'
export default {
  name: 'ImportImportantNodes' + Date.now(),
  props: {
    // 隐藏显示
    visible: {
      type: Boolean,
      require: true
    },
    // 选中项
    selected: {
      type: Array,
      require: true
    }
  },
  components: {
    BaseModal,
    UTable,
    UTableColumn
  },
  data() {
    return {
      // 全选节点
      all: {
        length: 0,
        checked: false,
        indeterminate: false
      },
      // 表头
      columns: [
        {
          width: 48,
          align: 'center',
          dataIndex: 'checkbox'
        },
        // {
        //   width: 48,
        //   align: 'center',
        //   dataIndex: 'selection'
        // },
        {
          title: '序号',
          width: 80,
          align: 'center',
          dataIndex: 'index'
        },
        {
          title: '阶段/类别',
          dataIndex: 'phaseCategory'
        },
        {
          title: '业务事项',
          dataIndex: 'businessMatters'
        },
        {
          title: '管控级别',
          width: 80,
          dataIndex: 'controlLevelName'
        },
        {
          title: '周期',
          width: 80,
          dataIndex: 'period'
        },
        {
          title: '计划开始日期',
          width: 120,
          dataIndex: 'planStartTime'
        },
        {
          title: '计划完成日期',
          width: 120,
          dataIndex: 'planEndTime'
        },
        {
          title: '完成标准',
          width: 150,
          dataIndex: 'completeStandard'
        },
        {
          title: '验证资料',
          width: 150,
          dataIndex: 'verifyFiles'
        },
        {
          title: '第一责任人',
          width: 200,
          dataIndex: 'firstResName'
        }
      ],
      // 一级节点选择
      controlLevel1: {
        length: 0,
        checked: false,
        indeterminate: false
      },
      // 二级节点选择
      controlLevel2: {
        length: 0,
        checked: false,
        indeterminate: false
      },
      // 三级节点选择
      controlLevel3: {
        length: 0,
        checked: false,
        indeterminate: false
      },
      // 表格数据
      data: [],
      // 加载
      loading: false,
      // 是否有数据
      isHasData: true,
      // 提交
      submiting: false
    }
  },
  watch: {
    // 监听显示字段获取数据
    visible: {
      handler(newV, oldV) {
        if (newV) {
          const obj = {
            length: 0,
            checked: false,
            indeterminate: false
          }
          this.controlLevel1 = JSON.parse(JSON.stringify(obj))
          this.controlLevel2 = JSON.parse(JSON.stringify(obj))
          this.controlLevel3 = JSON.parse(JSON.stringify(obj))
          this.all = JSON.parse(JSON.stringify(obj))
          this.$nextTick(() => {
            this.getData()
          })
        }
      }
    }
  },
  computed: {
    ...mapGetters(['GET_REDRESS_PERCENTAGE']),
    // 地址携带信息
    info() {
      return this.$route.query
    }
  },
  methods: {
    /**
     * @description: 预处理数据
     * @param {array} tree 树数据
     * @return {array} 处理后的数据
     */
    handleData(tree) {
      tree.forEach((item) => {
        item.checked = false
        item.indeterminate = false
        // 统计总节点数
        this.all.length++
        // 统计各个级别节点数
        if (item.controlLevelId) this['controlLevel' + item.controlLevelId].length++
        if (item.childTree) {
          this.handleData(item.childTree)
        } else {
          item.childTree = []
        }
      })
      return tree
    },
    /**
     * @description: 获取表格数据
     * @param {void}
     * @return {void}
     */
    async getData() {
      const { id: planTaskDetailId, version } = this.info
      this.loading = true
      const {
        code,
        data: { treeListVO }
      } = await controlPlanningImportantNodes.queryScheduleMasterPlan({
        latestData: version ? false : true,
        planTaskDetailId,
        version
      })
      if (code === 200) {
        if (treeListVO.length > 0) {
          this.isHasData = true
          this.data = this.handleData(treeListVO)
          this.$refs.table.reloadData(this.data).then(async () => {
            this.$refs.table.setAllTreeExpansion()
            this.selected.forEach((el) => {
              this.handleChange(el, true)
            })
            await this.handleUpdate()
            this.loading = false
          })
        } else {
          this.isHasData = false
        }
      } else {
        this.data = []
        this.isHasData = false
      }
    },
    /**
     * @description: 找到当前操作的节点
     * @param {string} id 节点id
     * @param {object} data 节点对象
     * @param {array} r 子节点
     * @return {array} 子节点
     */
    findItem(id, data, r) {
      for (let i = 0; i < data.length; i++) {
        if (data[i].id === id) {
          r = data[i]
          break
        }
        if (data[i].childTree.length > 0) {
          r = this.findItem(id, data[i].childTree, r)
        }
      }
      return r
    },
    /**
     * @description: 根据当前节点向下处理
     * @param {object} unit 当前节点
     * @param {boolean} bool 状态
     * @return {void}
     */
    handleLower(unit, bool) {
      unit.childTree.forEach((item) => {
        item.checked = bool
        item.indeterminate = false
        this.handleLower(item, bool)
      })
    },
    /**
     * @description: 根据当前节点向上处理
     * @param {object} unit 当前节点
     * @return {void}
     */
    handleUpper(unit) {
      let unitParent = this.findItem(unit.parentId, this.data) //  找到 unit 的父级
      if (!unitParent) return
      const len = unitParent.childTree.length //   记录一下 parentUnit 有多少个子级
      let count = 0 //  记录子级勾选数
      let half = 0 //  记录子级半勾选数
      //   遍历父级
      unitParent.childTree.forEach((item) => {
        if (item.checked === true) count++
        if (item.indeterminate === true) half++

        // 如果子级中有勾选
        if (count > 0) {
          // 如果勾选数等于子级数，则勾选父级，并取消父级半勾选
          if (count === len) {
            unitParent.checked = true
            unitParent.indeterminate = false
          }
          // 如果不等于，则不勾选父级，添加父级半勾选
          else {
            unitParent.checked = false
            unitParent.indeterminate = true
          }
        }
        // 如果子级没有勾选
        else {
          unitParent.checked = false
          // 根据子级半勾选数决定父级是否半勾选
          unitParent.indeterminate = half > 0
        }
      })
      //   递归向上处理
      this.handleUpper(unitParent)
    },
    /**
     * @description: 找到所有符合条件的节点
     * @param {number} index 节点序号
     * @param {array} data 树数据
     * @param {array} r 符合条件的节点
     * @return {array} 符合条件的节点
     */
    findSelectNode(index, data, r = []) {
      for (let i = 0; i < data.length; i++) {
        if (data[i].controlLevelId == index) {
          r.push(data[i])
        }
        if (data[i].childTree.length > 0) {
          r = this.findSelectNode(index, data[i].childTree, r)
        }
      }
      return r
    },
    /**
     * @description: 节点选中
     * @param {object} row 行数据
     * @param {event} e 事件对象
     * @return {void}
     */
    async handleNodeChecked(row, e) {
      this.loading = true
      this.handleChange(row, e.target.checked)
      await this.handleUpdate()
      this.loading = false
    },
    /**
     * @description: 处理多选点击，当前节点状态，全选状态，顶部多级别节点选择状态
     * @param {object} row 当前节点
     * @param {boolean} bool 状态
     * @return {void}
     */
    handleChange(row, bool) {
      const current = this.findItem(row.id, this.data)
      if (!current) return
      current.checked = bool //  处理当前节点勾选状态
      current.indeterminate = false //  无论勾选还是取消，只要操作了当前节点，该节点都不应该处于半选状态
      // 沿着当前节点向上处理
      this.handleUpper(current, bool)
      // 沿着当前节点向下处理
      this.handleLower(current, bool)
      // 处理【顶部左侧】三个按钮
      let temp = {
        checked1: 0, //  记录节点级别 === "1" 的节点的勾选数
        checked2: 0,
        checked3: 0
      }
      // 判断节点上存在节点级别字段且有值的节点，分别记录每个值处于勾选状态的数量
      function recursion(data) {
        data.forEach((item) => {
          if (item.controlLevelId && item.checked === true) {
            temp['checked' + item.controlLevelId]++
          }
          if (item.childTree) {
            recursion(item.childTree)
          }
        })
      }
      recursion(this.data)
      // 集中处理节点级别选中状态
      const batch = (v) => {
        if (temp['checked' + v] > 0) {
          if (temp['checked' + v] === this['controlLevel' + v].length) {
            this['controlLevel' + v].checked = true
            this['controlLevel' + v].indeterminate = false
          } else {
            this['controlLevel' + v].checked = false
            this['controlLevel' + v].indeterminate = true
          }
        } else {
          this['controlLevel' + v].checked = false
          this['controlLevel' + v].indeterminate = false
        }
      }
      batch('1')
      batch('2')
      batch('3')
      // 处理【全选】
      let lv1Count = 0 //  记录第一层的勾选数
      let lv1Half = 0 //  记录第一层的半勾选数
      const lv1Len = this.data.length //  记录第一层总数
      this.data.forEach((item) => {
        if (item.checked === true) lv1Count++
        if (item.indeterminate === true) lv1Half++
      })
      if (lv1Count > 0) {
        if (lv1Count === lv1Len) {
          this.all.checked = true
          this.all.indeterminate = false
        } else {
          this.all.checked = false
          this.all.indeterminate = true
        }
      } else {
        this.all.checked = false
        this.all.indeterminate = lv1Half > 0
      }
    },
    /**
     * @description: 管控级别节点选择,关联全选状态，单一节点状态
     * @param {number} index 节点序号
     * @param {event} event 事件
     * @return {void}
     */
    async handleSelectNode(index, event) {
      const {
        target: { checked }
      } = event
      // 修改节点选择状态
      this['controlLevel' + index].checked = checked
      this['controlLevel' + index].indeterminate = false
      // 找到所有符合条件的节点
      const nodes = this.findSelectNode(index, this.data)
      this.loading = true
      // 对每个对应的元素调用单一节点勾选事件
      nodes.forEach((item) => {
        this.handleChange(item, checked)
      })
      await this.handleUpdate()
      this.loading = false
    },
    /**
     * @description: 全选，并关联节点级别选中
     * @param {boolean} bool 状态
     * @return {void}
     */
    async handleAll(bool) {
      this.loading = true
      // 递归全选或全部取消
      function recursion(data, bool) {
        data.forEach((item) => {
          item.checked = bool
          item.indeterminate = false
          if (item.childTree) {
            recursion(item.childTree, bool)
          }
        })
      }
      // 处理【全选】按钮自身
      this.all.indeterminate = false
      this.all.checked = bool
      // 处理三个节点级别选中按钮
      this.controlLevel1.indeterminate = false
      this.controlLevel1.checked = bool
      this.controlLevel2.indeterminate = false
      this.controlLevel2.checked = bool
      this.controlLevel3.indeterminate = false
      this.controlLevel3.checked = bool
      // 处理【节点树】
      recursion(this.data, bool)
      await this.handleUpdate()
      this.loading = false
    },
    /**
     * @description: 更新
     * @param {void}
     * @return {void}
     */
    handleUpdate() {
      return new Promise(async (resolve, reject) => {
        setTimeout(async () => {
          const expandRecords = this.$refs.table.getTreeExpandRecords()
          // 获取之前滚动高度(表格实例上的scrollTop属性，在滚动到底部时会小于真实的scrollTop值，因此直接从dom获取真实滚动高度)
          const scrollTop = this.$refs.table.tableExample().bodyWrapper.scrollTop
          const scrollLeft = this.$refs.table.tableExample().bodyWrapper.scrollLeft
          // 加载数据
          await this.$refs.table.reloadData(this.data)
          // 数据加载完成出现之后，打开之前的展开行
          expandRecords.forEach((row) => {
            this.$refs.table.setTreeExpansion(row, true)
          })
          // 还原之前滚动高度
          this.$refs.table.pagingScrollTopLeft(scrollTop + 1, scrollLeft)
          this.$nextTick(()=>{
            // 不加这一步，列表操作栏 会变形
            this.$refs.table.pagingScrollTopLeft(scrollTop, scrollLeft)
          })
          resolve()
        }, 0)
      })
    },
    /**
     * @description: 获取选中项id
     * @param {array} tree 树数据
     * @param {array} checkedNodes 树数据
     * @param {array} indeterminateNodes 树数据
     * @return {void}
     */
    getTreeChecked(tree, checkedNodes = [], indeterminateNodes = []) {
      tree.forEach((item) => {
        if (item.checked && item.nodeType === 1) {
          checkedNodes.push(item)
        }
        if (item.indeterminate) indeterminateNodes.push(item.id)
        if (item.childTree) {
          this.getTreeChecked(item.childTree, checkedNodes, indeterminateNodes)
        }
      })
      return { checkedNodes, indeterminateNodes }
    },
    /**
     * @description: 确定
     * @param {void}
     * @return {void}
     */
    handleConfirm() {
      const { checkedNodes } = this.getTreeChecked(this.data)
      this.$emit('update:selected', checkedNodes)
      this.data = []
      this.handleModalCancel()
    },
    /**
     * @description: 关闭模态框
     * @param {void}
     * @return {void}
     */
    handleModalCancel() {
      this.$emit('update:visible', false)
    }
  }
}
</script>
<style lang="less" scoped>
@deep: ~'>>>';
.import-important-nodes-wrapper {
  margin-bottom: 20px;
}
@{deep} .import-important-nodes-table .el-table td .cell {
  overflow: visible;
}
.span-ellipsis {
  width: 100%;
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all;
}
@{deep} .el-table {
  .select {
    background-color: #ecf5ff !important;
    > td {
      background-color: #ecf5ff !important;
    }
  }
}
.all-checked {
  position: absolute;
  top: 56px;
  left: 8.5px;
  z-index: 999;
}
</style>
